/*
 * MIT License
 *
 * Copyright (c) 2023-present, tangli
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package tony.core.model

import com.fasterxml.jackson.annotation.JsonIgnore
import io.swagger.v3.oas.annotations.media.Schema

/**
 * 可组装树形结构
 *
 * @author tangli
 * @date 2025/07/16 11:36
 */
public interface ForestLike<T : ForestLike<T>> : TreeLike<T> {
    /**
     * 节点编码, 用于区分节点位置
     *
     * @return [String]
     * @author tangli
     * @date 2025/07/16 11:37
     */
    public val codeSeq: String?

    /**
     * 获取节点分隔符.
     *
     * @return [String]
     * @author tangli
     * @date 2025/07/16 11:39
     */
    @get:Schema(hidden = true)
    @get:JsonIgnore
    public val splitter: String
        get() = "-"

    /**
     * 是否根节点.
     *
     * @return boolean
     * @author tangli
     * @date 2025/07/16 11:40
     */
    @get:Schema(hidden = true)
    @get:JsonIgnore
    public val isRoot: Boolean
        get() =
            !(
                if (codeSeq.isNullOrBlank()) {
                    ""
                } else {
                    codeSeq.toString()
                }
            ).contains(splitter)

    /**
     * 节点级别.
     *
     * 根节点为 0.
     * @author tangli
     * @date 2025/07/16 11:40
     */
    public val level: Int
        get() {
            val internalCode = codeSeq
            return if (isRoot || internalCode.isNullOrBlank()) {
                0
            } else {
                internalCode.split(splitter).size
            }
        }

    /**
     * 获取排序.
     *
     * @return int
     * @author tangli
     * @date 2025/07/16 11:42
     */
    @get:JsonIgnore
    public val sort: Int?

    override val children: MutableCollection<T>

    /**
     * 判断 otherCode 是否为当前节点的直接子节点。
     * 规则：
     * 1. 必须以 "$codeSeq$splitter" 开头。
     * 2. 剩余部分（suffix）不能为空，且不能再包含 splitter。
     * @param otherCode 其他代码
     * @return boolean
     * @author tangli
     * @date 2025/07/16 11:51
     */
    public fun isChildNode(otherCode: String?): Boolean {
        val prefix = codeSeq + splitter
        if (otherCode?.startsWith(prefix) == false) return false
        val suffix =
            (
                if (otherCode.isNullOrBlank()) {
                    ""
                } else {
                    otherCode
                }
            ).removePrefix(prefix)
        return suffix.isNotEmpty() && !suffix.contains(splitter)
    }
}
